home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / rpg / crossfir.92 / crossfir / crossfire-0.92.5 / server / attack.c < prev    next >
C/C++ Source or Header  |  1996-07-24  |  47KB  |  1,480 lines

  1. /*
  2.  * static char *rcsid_attack_c =
  3.  *   "$Id: attack.c,v 1.30 1996/07/24 07:34:02 master Exp master $";
  4.  */
  5. /*
  6.     CrossFire, A Multiplayer game for X-windows
  7.  
  8.     Copyright (C) 1992 Frank Tore Johansen
  9.  
  10.     This program is free software; you can redistribute it and/or modify
  11.     it under the terms of the GNU General Public License as published by
  12.     the Free Software Foundation; either version 2 of the License, or
  13.     (at your option) any later version.
  14.  
  15.     This program is distributed in the hope that it will be useful,
  16.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.     GNU General Public License for more details.
  19.  
  20.     You should have received a copy of the GNU General Public License
  21.     along with this program; if not, write to the Free Software
  22.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  23.  
  24.     The author can be reached via e-mail to frankj@ifi.uio.no.
  25. */
  26. #include <global.h>
  27. #include <living.h>
  28.  
  29. #ifndef __CEXTRACT__
  30. #include <sproto.h>
  31. #endif
  32. #ifdef SOUND_EFFECTS
  33. #include <sounds.h>
  34. #endif
  35. /* Version 0.92.5 made some pretty good size changes - if you want the old
  36.  * code, comment this out.  Old code only left in if there are problems -
  37.  * that is why this isn't a standard config option.
  38.  */
  39. #define NEW_HIT_PLAYER
  40. /*#define ATTACK_DEBUG*/
  41.  
  42. /* did_make_save_item just checks to make sure the item actually
  43.  * made its saving throw based on the tables.  It does not take
  44.  * any further action (like destroying the item).
  45.  */
  46.  
  47. int did_make_save_item(object *op, int type) {
  48.   int i, saves=0,materials=0;
  49.  
  50.   type &= (~op->immune | ~op->protected);
  51.  
  52.   if(type&AT_CANCELLATION)
  53.     type=15;
  54.   else if(type&AT_COLD)
  55.     type=4;
  56.   else if(type&AT_ELECTRICITY)
  57.     type=3;
  58.   else if(type&AT_FIRE)
  59.     type=2;
  60.   else if(type&AT_PHYSICAL)
  61.     type=0;                     /* This was 1 before... */
  62.   else if(type==AT_MAGIC) /* Only pure magic, not paralyze, etc */
  63.     type=1;                     /* This was 0 before... */
  64.   else return 1;
  65.   for(i=0;i<NROFMATERIALS;i++)
  66.     if(op->material&(1<<i)) {
  67.       materials++;
  68.       if(RANDOM()%20+1>=object_saves[type][i]-op->magic)
  69.     saves++;
  70.     }
  71.   if (saves==materials || materials==0) return 1;
  72.   if ((saves==0) || (RANDOM()%materials+1 > saves)) return 0;
  73.   return 1;
  74. }
  75.  
  76. /* This function calls did_make_save_item.  It then performs the
  77.  * appropriate actions to the item (such as burning the item up,
  78.  * calling cancellation, etc.)
  79.  */
  80.  
  81. void save_throw_object(object *op, int type) {
  82.  
  83.     if (!did_make_save_item(op, type)) {
  84.     object *env=op->env;
  85.     int x=op->x,y=op->y;
  86.     mapstruct *m=op->map;
  87.  
  88.     /* Hacked the following so that type LIGHTER will work. 
  89.      * Also, objects which are potenital "lights" that are hit by 
  90.      * flame/elect attacks will be set to glow. "lights" are any 
  91.      * object with +/- glow_radius and an "other_arch" to change to. 
  92.      * (and please note that we cant fail our save and reach this 
  93.      * function if the object doesnt contain a material that can burn. 
  94.      * So forget lighting magical swords on fire with this!) -b.t.
  95.      */ 
  96.     if(type&(AT_FIRE|AT_ELECTRICITY)
  97.            &&op->other_arch&&op->glow_radius) { 
  98.         char *arch=op->other_arch->name;
  99.  
  100.         if(op->nrof) op->nrof--;
  101.         else { 
  102.                   remove_ob(op);
  103.                   free_object(op);
  104.         }
  105.         if((op = get_archetype(arch))!=NULL)
  106.                    if(env) {  
  107.                       op->x=env->x,op->y=env->y;
  108.                       insert_ob_in_ob(op,env);
  109.                    } else { 
  110.                       op->x=x,op->y=y;
  111.                       insert_ob_in_map(op,m);
  112.                    }    
  113.         return;
  114.         }
  115.         if(type&AT_CANCELLATION) {          /* Cancellation. */
  116.               cancellation(op);
  117.               return;  
  118.         }
  119.     if(op->nrof>1)
  120.           decrease_ob_nr(op,RANDOM()%op->nrof);
  121.     else {
  122.           remove_ob(op);
  123.           free_object(op);
  124.     }
  125.     if(type&(AT_FIRE|AT_ELECTRICITY)) {
  126.           op=get_archetype("burnout");
  127.           if(env) {
  128.         op->x=env->x,op->y=env->y;
  129.                 insert_ob_in_ob(op,env);
  130.           } else { 
  131.         op->x=x,op->y=y;
  132.               insert_ob_in_map(op,m);
  133.           }
  134.     }
  135.     return;
  136.     }
  137.     if(type&AT_COLD &&!(op->immune&type||op->protected&type) &&
  138.       !QUERY_FLAG(op,FLAG_NO_PICK)&&(RANDOM()&2)) {
  139.         object *tmp;
  140.         archetype *at = find_archetype("icecube");
  141.         if (at == NULL)
  142.           return;
  143.         if ((tmp = present_arch(at,op->map,op->x,op->y)) == NULL) {
  144.           tmp = arch_to_object(at);
  145.           tmp->x=op->x,tmp->y=op->y;
  146.           insert_ob_in_map(tmp,op->map);
  147.         }
  148.         remove_ob(op);
  149.         (void) insert_ob_in_ob(op,tmp);
  150.         return;
  151.     }
  152. }
  153.  
  154. int hit_map(object *op,int dir,int type) {
  155.   object *tmp,*next=NULL;
  156.   int retflag=0;  /* added this flag..  will return 1 if it hits a monster */
  157.  
  158.   if(out_of_map(op->map,op->x+freearr_x[dir],op->y+freearr_y[dir]))
  159.       return 0;
  160.  
  161.  /* peterm:  a few special cases for special attacktypes --counterspell
  162.         must be out here because it strikes things which are not alive*/
  163.   if(type&AT_COUNTERSPELL) {
  164.     counterspell(op);  /* see newspells.c */
  165.     if(!(type & ~(AT_COUNTERSPELL|AT_MAGIC))){
  166. #ifdef NO_CONE_PROPOGATE
  167.     return 1;
  168. #else
  169.     return 0;  /* we're done, no other attacks */
  170. #endif
  171.     }
  172.     type&= ~AT_COUNTERSPELL;
  173.   }
  174.  
  175.   if(type&AT_CHAOS) {
  176.     shuffle_attack(op,1);  /*1 flag tells it to change the face */
  177.     update_object(op);
  178.     type &= ~AT_CHAOS;
  179.   }
  180.  
  181.  
  182.   for(tmp=get_map_ob(op->map,op->x+freearr_x[dir],op->y+freearr_y[dir]);
  183.       tmp!=NULL;tmp=next)
  184.   {
  185.     next=tmp->above;
  186.  
  187.     /* Since we are traversing a stack, it is possible that the stack
  188.      * gets messed up.  So do some checks.
  189.      */
  190.     if (QUERY_FLAG(tmp, FLAG_FREED)) {
  191.     LOG(llevDebug,"Warning: in hit_map, found free object\n");
  192.     break;
  193.     }
  194.     else if(QUERY_FLAG(tmp,FLAG_ALIVE)) {
  195.       hit_player(tmp,op->stats.dam,op,type);
  196.       retflag |=1;
  197.     }
  198.     else if(tmp->material)
  199.       save_throw_object(tmp,type);
  200.   }
  201.   /*if(tmp==NULL) return 0;  This doesn't work, of course */
  202. #ifdef NO_CONE_PROPOGATE
  203.   return retflag;
  204. #else
  205.   return 0;
  206. #endif
  207. }
  208.  
  209. att_msg *attack_message(int dam) {
  210.   static att_msg messages;
  211.   static char buf1[MAX_BUF],buf2[MAX_BUF];
  212.   if(dam==-1) {
  213.     strcpy(buf1,"hit");
  214.     buf2[0]='\0';
  215.   } else if(dam==0) {
  216.     strcpy(buf1,"missed");
  217.     buf2[0]='\0';
  218.   } else if(dam<3) {
  219.     strcpy(buf1,"grazed");
  220.     buf2[0]='\0';
  221.   } else if(dam<6) {
  222.     strcpy(buf1,"hit");
  223.     buf2[0]='\0';
  224.   } else if(dam<9) {
  225.     strcpy(buf1,"hit");
  226.     strcpy(buf2," hard");
  227.   } else if(dam<12) {
  228.     strcpy(buf1,"hit");
  229.     strcpy(buf2," very hard");
  230.   } else if(dam<16) {
  231.     strcpy(buf1,"hit");
  232.     strcpy(buf2," extremely hard");
  233.   } else if(dam<20) {
  234.     strcpy(buf1,"crush");
  235.     strcpy(buf2," very hard");
  236.   } else if(dam<25) {
  237.     strcpy(buf1,"smash");
  238.     strcpy(buf2," with a bonecrunching sound");
  239.   } else if(dam<35) {
  240.     strcpy(buf1,"grind");
  241.     strcpy(buf2," to dust");
  242.   } else {
  243.     strcpy(buf1,"shred");
  244.     strcpy(buf2," to pieces");
  245.   }
  246.   messages.msg1=buf1,messages.msg2=buf2;
  247.   return &messages;
  248. }
  249.  
  250. /*
  251.  * attack_ob() returns 1 on a hit, and 0 on a miss.
  252.  */
  253.  
  254. int attack_ob(object *op,object *hitter) {
  255.   int roll,dam=0;
  256.   char buf[MAX_BUF];
  257.   unsigned int type,type_extra,ghosthit;
  258.   att_msg *msg;
  259.   char *op_name;
  260.   signed char luck=0;
  261.  
  262.   if(op->head!=NULL)
  263.     op=op->head;
  264.   if(op->name==NULL) {
  265.     if(debug) {
  266.       dump_object(op);
  267.       LOG(llevDebug,"Object without name tried to attack.\n%s\n",errmsg);
  268.     }
  269.     if (QUERY_FLAG(op, FLAG_REMOVED) && !QUERY_FLAG(op, FLAG_FREED))
  270.       free_object(op);
  271.     return 1;
  272.   }
  273.   /*
  274.    * A little check to make it more difficult to dance forward and back
  275.    * to avoid ever being hit by monsters.
  276.    */
  277.   if (QUERY_FLAG(op, FLAG_MONSTER) && op->speed_left > -(FABS(op->speed))*0.3) {
  278.  
  279.     /* Decrease speed BEFORE calling process_object.  Otherwise, an
  280.      * infinite loop occurs, with process_object calling move_monster,
  281.      * which then gets here again.  By decreasing the speed before
  282.      * we call process_object, the 'if' statement above will fail.
  283.      */
  284.     op->speed_left--;
  285.     process_object(op);
  286.     if (QUERY_FLAG(op, FLAG_FREED))
  287.       return 1;
  288.   }
  289.   add_refcount(op_name = op->name);
  290.   if(hitter->head!=NULL)
  291.     hitter=hitter->head;
  292.   if(op->stats.luck) {
  293.     luck=RANDOM()%abs(op->stats.luck);
  294.     if(op->stats.luck<0)
  295.       luck= -luck;
  296.   }
  297.   if((int)luck < -5)
  298.     roll= -20;
  299.   else
  300.     roll=RANDOM()%20+1+luck;
  301.  
  302.   /* See if we hit the creature */
  303.   if(roll==(20+luck)||op->stats.ac>=hitter->stats.wc-roll) {
  304.     int hitdam=hitter->stats.dam+luck;
  305. #ifdef CASTING_TIME
  306.    if ((hitter->type == PLAYER)&&(hitter->casting > -1)){
  307.      hitter->casting = -1;
  308.      hitter->spell_state = 1;
  309.      new_draw_info(NDI_UNIQUE, 0,hitter,"You attacked and lost your spell!");
  310.    }
  311.    if ((op->casting > -1)&&(hitdam > 0)){
  312.      op->casting = -1;
  313.      op->spell_state = 1;
  314.      if (op->type == PLAYER) 
  315.        new_draw_info(NDI_UNIQUE, 0,op,"You were hit and lost your spell!");
  316.      new_draw_info_format(NDI_ALL|NDI_UNIQUE,5,NULL,
  317.     "%s was hit by %s and lost a spell.",op->name,hitter->name);
  318.    }
  319. #endif
  320. /* Vick's (vick@bern.docs.uu.se) patch 921101 to make it
  321.    possible to create non-hitting monsters. */
  322. /* Originally was ..hitdam<=0....hitdam=1 */
  323.  
  324.     if (hitdam<0) hitdam=0;
  325.  
  326.     type=hitter->attacktype;
  327.     if(!type) type=AT_PHYSICAL;
  328.     ghosthit=type&AT_GHOSTHIT;
  329.     type&=~AT_GHOSTHIT;
  330.     type_extra = type & ~AT_PHYSICAL;
  331.  
  332.     /* Basically, if the attacktype includes something beyond just physical,
  333.      * cut damage in half and hit them with the special attack types.
  334.      * In this way, even if something is immune to physical, but your attack
  335.      * type is physical and fire, you still do some damage.
  336.      */
  337.     if(type_extra) {
  338.       hitdam=hitdam/2+1;
  339.       dam+=hit_player(op,RANDOM()%(hitdam)+1,hitter,
  340.                       type_extra|ghosthit);
  341.       if (QUERY_FLAG(op, FLAG_FREED))
  342.         goto leave;
  343.     }
  344.     /* I am pretty sure the following is same as type&~type_extra */
  345.     if(type&AT_PHYSICAL) {
  346.       if(QUERY_FLAG(op,FLAG_HITBACK) && QUERY_FLAG(hitter,FLAG_ALIVE)) {
  347.         if(op->attacktype&AT_ACID&&hitter->type==PLAYER)
  348.           new_draw_info(NDI_UNIQUE, 0,hitter,"You are splashed by acid!\n");
  349.         hit_player(hitter,RANDOM()%(op->stats.dam+1),op,op->attacktype);
  350.         if (QUERY_FLAG(op, FLAG_FREED))
  351.           goto leave;
  352.       }
  353.       /* Vick's (vick@bern.docs.uu.se) patch 921101 for non-hitter critters. */
  354.       if (hitdam>0)
  355.         dam+=hit_player(op,RANDOM()%(hitdam)+1,hitter,
  356.                       (type&AT_PHYSICAL)|ghosthit);
  357.       if (QUERY_FLAG(op, FLAG_FREED))
  358.         goto leave;
  359.     }
  360.   }
  361.   msg=attack_message(dam);
  362.  
  363.   /* Did a player hurt another player?  Inform both! */
  364.   if(op->type==PLAYER&&
  365.      (get_owner(hitter)==NULL?hitter->type:hitter->owner->type)==PLAYER)
  366.     {
  367.     if(get_owner(hitter)!=NULL)
  368.       sprintf(buf,"%s %ss you%s with %s.",
  369.               hitter->owner->name,msg->msg1,msg->msg2,hitter->name);
  370.     else
  371.       {
  372.     sprintf(buf,"%s %ss you%s.",hitter->name,msg->msg1,msg->msg2);
  373. #ifdef SOUND_EFFECTS
  374.     if (dam != 0) {
  375.       if (dam < 10)
  376.         play_sound_player_only(op->contr, SOUND_PLAYER_IS_HIT1);
  377.       else if (dam < 20)
  378.         play_sound_player_only(op->contr, SOUND_PLAYER_IS_HIT2);
  379.       else
  380.         play_sound_player_only(op->contr, SOUND_PLAYER_IS_HIT3);
  381.     }
  382. #endif
  383.       }
  384.     new_draw_info(NDI_BLACK, 0,op,buf);
  385.   }
  386.   if(hitter->type==PLAYER) {
  387.     sprintf(buf,"You %s %s%s.",msg->msg1,op_name,msg->msg2);
  388. #ifdef SOUND_EFFECTS
  389.     if (dam != 0) {
  390.       if (dam < 10)
  391.     play_sound_player_only(hitter->contr, SOUND_PLAYER_HITS1);
  392.       else if (dam < 20)
  393.     play_sound_player_only(hitter->contr, SOUND_PLAYER_HITS2);
  394.       else
  395.     play_sound_player_only(hitter->contr, SOUND_PLAYER_HITS3);
  396.     }
  397. #endif
  398.     new_draw_info(NDI_BLACK, 0, hitter, buf);
  399.   } else if(get_owner(hitter)!=NULL&&hitter->owner->type==PLAYER) {
  400.     sprintf(buf,"You %s %s%s with %s.",
  401.             msg->msg1,op_name,msg->msg2,hitter->name);
  402. #ifdef SOUND_EFFECTS
  403.     play_sound_map(op->map, op->x, op->y, SOUND_PLAYER_HITS4);
  404. #endif
  405.     new_draw_info(NDI_BLACK, 0, hitter->owner, buf);
  406.   }
  407.  leave:
  408.   free_string(op_name);
  409.   return dam;
  410. }
  411.  
  412. void tear_down_wall(object *op)
  413. {
  414.     int perc=0;
  415.  
  416.     if (!op->stats.maxhp) {
  417.     LOG(llevError, "TEAR_DOWN wall %s had no maxhp.\n", op->name);
  418.     perc = 1;
  419.     } else if(op->arch->animations==0) {
  420.     /* Object has been called - no animations, so remove it */
  421.     if(op->stats.hp<0) {
  422.         int x = op->x, y = op->y;
  423.         mapstruct *m = op->map;
  424.  
  425.         remove_ob(op); /* Should update LOS */
  426.         free_object(op);
  427.         update_position(m, x, y);
  428.     }
  429.     return;    /* no animations, so nothing more to do */
  430.     }
  431.     perc = op->arch->animations
  432.     - ((int)op->arch->animations*op->stats.hp)/op->stats.maxhp;
  433.     if (perc >= (int) op->arch->animations)
  434.     perc = op->arch->animations-1;
  435.     else if (perc < 1)
  436.     perc = 1;
  437.     op->face=&new_faces[op->arch->faces[perc]];
  438.     update_object(op);
  439.     if(perc==op->arch->animations-1) { /* Reached the last animation */
  440.     if(op->face==blank_face) {
  441.         /* If the last face is blank, remove the ob */
  442.         int x = op->x, y = op->y;
  443.         mapstruct *m = op->map;
  444.  
  445.         remove_ob(op); /* Should update LOS */
  446.         free_object(op);
  447.         update_position(m, x, y);
  448.  
  449.     } else { /* The last face was not blank, leave an image */
  450.         CLEAR_FLAG(op, FLAG_BLOCKSVIEW);
  451.         update_all_los(op->map);
  452.         CLEAR_FLAG(op, FLAG_NO_PASS);
  453.         CLEAR_FLAG(op, FLAG_ALIVE);
  454.     }
  455.     }
  456. }
  457.  
  458. /* This returns the amount of damage hitter does to op with the appropriate`
  459.  * attacktype.  Only 1 attacktype should be set at a time.  This doesn't
  460.  * damage the player, but returns how much it should take.  However, it will
  461.  * do other effects (paralyzation, slow, etc.)
  462.  */
  463.  
  464. int hit_player_attacktype(object *op, object *hitter, int dam, 
  465.     uint32 attacktype, int magic) {
  466.  
  467.     int does_slay=0;
  468.  
  469. #ifdef ATTACK_DEBUG
  470.     LOG(llevDebug, "\thit_player_attacktype: attacktype %x, dam %d\n",
  471.     attacktype, dam);
  472. #endif
  473.  
  474.     if (!attacktype) {
  475.     LOG(llevError,"hit_player_attacktype called without an attacktype\n");
  476.     return 0;
  477.     }
  478.  
  479.     if (hitter->slaying) {
  480.     if (((op->race !=NULL && strstr(op->race, hitter->slaying)) ||
  481. #ifndef MULTIPLE_GODS
  482.       (strstr(hitter->slaying, undead_name) && QUERY_FLAG(op,FLAG_UNDEAD)) ||
  483. #endif
  484.       (op->arch && op->arch->name!=NULL && strstr(op->arch->name, hitter->slaying))))
  485.         does_slay=1;
  486.         dam*=3;
  487.     }
  488.     if (op->vulnerable & attacktype) dam*=2;
  489.     if (op->protected & attacktype) dam/=2;
  490.  
  491.     /* Special hack.  By default, if immune to something, you shouldn't need
  492.      * to worry.  However, acid is an exception, since it can still damage
  493.      * your items.  Only include attacktypes if special processing is needed
  494.      */
  495.     if (!does_slay && (op->immune & attacktype) && (attacktype!=AT_ACID)) 
  496.     return 0;
  497.  
  498.     /* Keep this in order - makes things easier to find */
  499.  
  500.     if (attacktype & AT_PHYSICAL) {
  501.     if (op->armour) dam=((100-op->armour)*dam/100);
  502.  /* Don't need to do anything for magic, fire, electricity, cold */    
  503.     } else if (attacktype & 
  504.       (AT_CONFUSION|AT_POISON|AT_SLOW|AT_PARALYZE|AT_FEAR|AT_CANCELLATION|
  505.        AT_DEPLETE|AT_BLIND)) {
  506.  
  507.         if (op->speed && (QUERY_FLAG(op, FLAG_MONSTER) || op->type==PLAYER) &&
  508.           !(RANDOM()%((attacktype&AT_SLOW?6:3))) && 
  509.       (RANDOM()%20+((op->protected&attacktype)?5:1) < savethrow[op->level])) {
  510.       /* Player has been hit by something */
  511.         if (attacktype & AT_CONFUSION) confuse_player(op,hitter,dam);
  512.         else if (attacktype & AT_POISON) poison_player(op,hitter,dam);
  513.         else if (attacktype & AT_SLOW) slow_player(op,hitter,dam);
  514.         else if (attacktype & AT_PARALYZE) paralyze_player(op,hitter,dam);
  515.         else if (attacktype & AT_FEAR) SET_FLAG(op, FLAG_SCARED);
  516.         else if (attacktype & AT_CANCELLATION) cancellation(op);
  517.         else if (attacktype & AT_DEPLETE) drain_stat(op);
  518.         else if (attacktype & AT_BLIND && !QUERY_FLAG(op,FLAG_UNDEAD) &&
  519.          !QUERY_FLAG(op,FLAG_GENERATOR)) blind_player(op,hitter,dam);
  520.     }
  521.     dam=0;    /* Confusion is an effect - doesn't damage */
  522.     }
  523.     else if (attacktype & AT_ACID) {
  524.     if (!(op->immune & AT_ACID ) && !(op->protected & AT_ACID)) {
  525.         object *tmp;  /*  If someone is both immune and protected from acid, so is his stuff */
  526.         int flag=0;
  527.         char buf[256];
  528.  
  529.         for(tmp=op->inv;tmp!=NULL;tmp=tmp->below) {
  530.         if(!QUERY_FLAG(tmp,FLAG_APPLIED)||tmp->immune&AT_ACID||
  531.            (tmp->protected&AT_ACID&&RANDOM()&1))
  532.             continue;
  533.         if(!(tmp->material&M_IRON))
  534.             continue;
  535.         if(tmp->magic< -4) /* Let's stop at -5 */
  536.             continue;
  537.         if(tmp->type==RING||tmp->type==GLOVES||tmp->type==BOOTS||
  538.            tmp->type==GIRDLE||tmp->type==AMULET||tmp->type==WAND||
  539.            tmp->type==ROD||tmp->type==HORN)
  540.             continue; /* To avoid some strange effects */
  541.         /* High damage acid has better chance of corroding objects */
  542.         if(RANDOM()%(dam+5)>RANDOM()%40) {
  543.             if(op->type==PLAYER) {
  544.             strcpy(buf,"The ");
  545.             strcat(buf,query_name(hitter));
  546.             strcat(buf,"'s acid corrodes your ");
  547.             strcat(buf,query_name(tmp));
  548.             strcat(buf,"!");
  549.             if (op->contr->eric_server > 0)
  550.                 esrv_send_item(op, tmp);
  551.             new_draw_info(NDI_UNIQUE, 0,op,buf);
  552.             flag=1;
  553.             }
  554.             tmp->magic--;
  555.         }
  556.         }
  557.         if(flag) {    /* Something was corroded */
  558.         if (op->contr->eric_server <= 0)
  559.             draw_all_inventory(op);
  560.         fix_player(op);
  561.         }
  562.     }
  563.     /* Get around check up above */
  564.     if (op->immune & AT_ACID && !does_slay) dam=0;
  565.     }
  566.     else if (attacktype & AT_DRAIN) {
  567.     if(op->stats.exp<=((op->protected & attacktype)?100:50)) {
  568.         if(op->type==GOLEM)
  569.         dam=999; /* It's force is "sucked" away. 8) */
  570.         else /* If we can't drain, lets try to do physical damage */
  571.         dam=hit_player_attacktype(op, hitter, dam, AT_PHYSICAL, magic);
  572.     } else {
  573.         if(hitter->stats.hp<hitter->stats.maxhp &&
  574.            (op->level > hitter->level) &&
  575.            RANDOM()%(op->level-hitter->level+3)>3)
  576.             hitter->stats.hp++;
  577.         if(!QUERY_FLAG(op,FLAG_WAS_WIZ))
  578.         add_exp(hitter,op->stats.exp/(100+(op->protected&attacktype)?100:0));
  579.         add_exp(op,-op->stats.exp/(50+(op->protected&attacktype)?50:0));
  580.         dam=0;    /* Drain is an effect */
  581.     }
  582.     /* weaponmagic, ghosthit not needed, poison, slow, paralyze handled above */
  583.     } else if (attacktype & AT_TURN_UNDEAD) {
  584.     if (QUERY_FLAG(op,FLAG_UNDEAD)) {
  585.         object *owner=get_owner(hitter)==NULL?hitter:get_owner(hitter);
  586.  
  587.         if(op->level<turn_bonus[owner->stats.Wis]+owner->level)
  588.         SET_FLAG(op, FLAG_SCARED);
  589.     }
  590.     else dam=0; /*don't damage non undead - should we damage undead? */
  591.     /* fear, cancelleation, deplete handled above */
  592.     } else if (attacktype & AT_DEATH) {
  593.      deathstrike_player(op, hitter, &dam);
  594.     } else if (attacktype & AT_CHAOS) {
  595.     dam=0;    /* I think this is right - Chaos attacks with other types */
  596.     }
  597.     else if (attacktype & AT_COUNTERSPELL) {
  598.     dam=0;    /* I don't think it is supposed to attack things */
  599.  
  600.     /* Godpower does normal effect? */
  601.     } else if (attacktype & AT_HOLYWORD) {
  602.     /* Holyword only effects a limited range of creatures */
  603.     if (op->race && hitter->slaying && strstr(hitter->slaying,op->race)) {
  604.         object *owner=get_owner(hitter)==NULL?hitter:get_owner(hitter);
  605.  
  606.         if(op->level<turn_bonus[owner->stats.Wis]+owner->level)
  607.         SET_FLAG(op, FLAG_SCARED);
  608.     }
  609.     else dam=0;    /* If not one of the creatures, no effect */
  610.     }
  611.     /* blindness handled with other effects above */
  612.     return dam;
  613. }
  614.              
  615.  
  616. /* This isn't used just for players, but in fact most objects.
  617.  * op is the object to be hit, dam is the amount of damage, hitter
  618.  * is what is hitting the object, and type is the attacktype.
  619.  * dam is base damage - protections/vulnerabilities/slaying matches can
  620.  * modify it.
  621.  */
  622.  
  623.   /* Oct 95 - altered the following slightly for MULTIPLE_GODS hack 
  624.    * which needs new attacktype AT_HOLYWORD to work . b.t. */
  625.  
  626. int hit_player(object *op,int dam, object *hitter, int type) {
  627.   char buf[MAX_BUF];
  628.   object *old_hitter=NULL; /* this is used in case of servant monsters */ 
  629.  
  630.   if(op->head!=NULL) {
  631.     if(op->head==op) {
  632.       LOG(llevError,"Recursive head error!\n");
  633.       return 0;
  634.     }
  635.     /* To paralyze/slow a creature, we must hit its head with the attacktype.
  636.      * If we are going to do this, this should probably be expanded.
  637.      */
  638.     if(type&AT_PARALYZE || type&AT_SLOW)
  639.       return 0;
  640.     op=op->head;
  641.   }
  642.   if(op->type==DOOR && op->inv && op->inv->type==RUNE)
  643.     spring_trap(op->inv,hitter);
  644.   /* If its already dead, or we're the wizard, don't attack it - no point */
  645.   if(QUERY_FLAG(op,FLAG_WIZ)||!QUERY_FLAG(op,FLAG_ALIVE)||op->stats.hp<0)
  646.     return 0;
  647.  
  648. #ifdef NEW_HIT_PLAYER
  649.   {
  650.     int maxdam=0,attacktype=1,attacknum,magic=(type & AT_MAGIC);
  651.  
  652.     /* By default, if a creature is immune to magic, it is immune to any
  653.      * attacktype that has magic as part of it.
  654.      */
  655. #ifdef ATTACK_DEBUG
  656.     LOG(llevDebug,"hit player: attacktype %d, dam %d\n", type, dam);
  657. #endif
  658.     if ((type & AT_MAGIC) && (op->immune & AT_MAGIC)) return 0;
  659.  
  660.     for (attacknum=0; attacknum<NROFATTACKS; attacknum++, attacktype=attacktype<<1) {
  661.  
  662.  
  663.     /* Magic isn't really a true attack type - it gets combined with other
  664.      * attack types.  As such, skip it over.  However, if magic is
  665.      * the only attacktype in the group, then still attack with it
  666.      */
  667.     if ((attacktype==AT_MAGIC) && (type & ~AT_MAGIC)) continue;
  668.  
  669.     /* Go through and hit the player with each attacktype, one by one.
  670.      * hit_player_attacktype only figures out the damage, doesn't inflict
  671.      * it.  It will do the appropriate action for attacktypes with
  672.      * effects (slow, paralization, etc.
  673.          */
  674.     if (type & attacktype) {
  675.         dam=hit_player_attacktype(op,hitter,dam,attacktype,magic);
  676.         maxdam=(maxdam>dam)?maxdam:dam;
  677.     }
  678.     }
  679.     CLEAR_FLAG(op,FLAG_SCARED); /* Or the monster won't hit back */
  680.     if(get_owner(hitter))
  681.     op->enemy=hitter->owner;
  682.     else if (QUERY_FLAG(hitter,FLAG_ALIVE))
  683.     op->enemy=hitter;
  684.     if(QUERY_FLAG(op,FLAG_UNAGGRESSIVE) && op->type != PLAYER) {
  685.     /* The unaggressives look after themselves 8) */
  686.     CLEAR_FLAG(op, FLAG_UNAGGRESSIVE);
  687.     npc_call_help(op);
  688.     }
  689.     if(type&AT_MAGIC && (RANDOM()%20+1)>=savethrow[op->level])
  690.     maxdam=maxdam/2;
  691.     op->stats.hp-=maxdam;
  692.  
  693.     /* Eneq(@csd.uu.se): Check to see if monster runs away. */
  694.     if ((op->stats.hp>=0) && 
  695.       (QUERY_FLAG(op, FLAG_MONSTER) || op->type == PLAYER) &&
  696.     op->stats.hp<(signed short)(((float)op->run_away/(float)100)*
  697.     (float)op->stats.maxhp)) {
  698.         if (QUERY_FLAG(op, FLAG_MONSTER))
  699.         SET_FLAG(op, FLAG_RUN_AWAY);
  700.         else
  701.         SET_FLAG(op, FLAG_SCARED);
  702.     }
  703.  
  704.     if(QUERY_FLAG(op,FLAG_TEAR_DOWN)) {
  705.     tear_down_wall(op);
  706.     return maxdam;    /* nothing more to do for wall */
  707.     }
  708.     /* Object has been killed.  Lets clean it up */
  709.     if(op->stats.hp<0) {
  710.     object *owner=NULL;
  711.     maxdam+=op->stats.hp+1;
  712.     if(QUERY_FLAG(op,FLAG_BLOCKSVIEW))
  713.         update_all_los(op->map); /* makes sure los will be recalculated */
  714.  
  715.     if(op->type==DOOR) {
  716.         op->speed = 0.1;
  717.         update_ob_speed(op);
  718.         op->speed_left= -0.05;
  719.         return maxdam;
  720.     }
  721.     if(op->type==GOLEM) {
  722.         remove_friendly_object(op);
  723.         if(get_owner(op)!=NULL)
  724.         op->owner->contr->golem=NULL;
  725.         else
  726.         LOG(llevDebug,"Encountered golem without owner.\n");
  727.         remove_ob(op);
  728.         free_object(op);
  729.         return maxdam;
  730.     }
  731.  
  732.     /* Now lets start dealing with experience we get for killing something */
  733.     owner=get_owner(hitter);
  734.     if(owner==NULL)
  735.         owner=hitter;
  736.  
  737.     /* Player killed something */
  738.     if(owner->type==PLAYER&&(owner->level/2<op->level||op->stats.exp>1000)) {
  739.         if(owner!=hitter) {
  740.         (void) sprintf(buf,"You killed %s with %s.",op->name,hitter->name);
  741. #ifdef ALLOW_SKILLS
  742.         old_hitter = hitter;
  743.         owner->exp_obj=hitter->exp_obj; 
  744. #endif
  745.         } else
  746.         (void) sprintf(buf,"You killed %s.",op->name);
  747. #ifdef SOUND_EFFECTS
  748.         play_sound_map(owner->map, owner->x, owner->y, SOUND_PLAYER_KILLS);
  749. #endif
  750.         new_draw_info(NDI_BLACK, 0,owner,buf);
  751.         if(op->type == PLAYER && hitter != op)
  752.          change_luck(hitter, -1);
  753.     }
  754.  
  755.     /* Pet killed something. */
  756.     if(get_owner(hitter)!=NULL) {
  757.         (void) sprintf(buf,"%s killed %s with %s.",hitter->owner->name,op->name,
  758.         hitter->name);
  759. #ifdef ALLOW_SKILLS
  760.         old_hitter = hitter;
  761.         owner->exp_obj=hitter->exp_obj;
  762. #endif
  763.         hitter=hitter->owner;
  764.     }
  765.     else
  766.         (void) sprintf(buf,"%s killed %s.",hitter->name,op->name);
  767.  
  768.     /* If you didn't kill yourself, and your not the wizard */
  769.     if(hitter!=op&&!QUERY_FLAG(op, FLAG_WAS_WIZ)) {
  770.         int exp=op->stats.exp;
  771.  
  772.         if(hitter->level>op->level)
  773.         exp=(exp*(op->level+1))/MAX(hitter->level+1, 1);
  774.  
  775. /* new exp system in here. Try to insure the right skill is modifying gained exp */ 
  776. #ifdef ALLOW_SKILLS 
  777.         if(hitter->type==PLAYER && !old_hitter) 
  778.         exp = calc_skill_exp(hitter,op); 
  779.         /* case for attack spells, summoned monsters killing */ 
  780.         if (old_hitter && hitter->type==PLAYER) {    
  781.         object *old_skill = hitter->chosen_skill; 
  782.  
  783.         hitter->chosen_skill=old_hitter->chosen_skill;
  784.         exp = calc_skill_exp(hitter,op); 
  785.         hitter->chosen_skill = old_skill;
  786.         }
  787. #endif /* ALLOW_SKILLS */
  788.  
  789.         /* Really don't give much experience for killing other players */
  790.         if (op->type==PLAYER)
  791.         exp/=10;
  792.  
  793. #ifdef SIMPLE_PARTY_SYSTEM
  794.         exp=exp/2;
  795.         if(hitter->type!=PLAYER || hitter->contr->party_number<=0)
  796.         add_exp(hitter,exp);
  797.         else {
  798.         int shares=0,count=0;
  799.         player *pl;
  800.         int no=hitter->contr->party_number;
  801.  
  802.         for(pl=first_player;pl!=NULL;pl=pl->next) {
  803.             if(pl->ob->contr->party_number==no && (pl->ob->map == hitter->map)) {
  804.             count++;
  805.             shares+=(pl->ob->level+4);
  806.             }
  807.         }
  808.         if(count==1 || shares>exp)
  809.             add_exp(hitter,exp);
  810.         else {
  811.             int share=exp/shares,given=0,nexp;
  812.             for(pl=first_player;pl!=NULL;pl=pl->next) {
  813.             if(pl->ob->contr->party_number==no && (pl->ob->map == hitter->map)) {
  814.                 nexp=(pl->ob->level+4)*share;
  815.                 add_exp(pl->ob,nexp);
  816.                 given+=nexp;
  817.                 if(pl->ob!=hitter)
  818.                 draw_stats(pl->ob);
  819.             }
  820.             }
  821.             exp-=given;
  822.             add_exp(hitter,exp); /* give any remainder to the player */
  823.         }
  824.         }
  825. #else /* SIMPLE_PARTY_SYSTEM */
  826.         add_exp(hitter,exp/2);
  827. #endif /* SIMPLE_PARTY_SYSTEM */
  828.     }
  829.     if(hitter->type==PLAYER)
  830.         draw_stats(hitter);
  831.     if(op->type!=PLAYER) {
  832.         new_draw_info(NDI_ALL, 10, NULL, buf);
  833.         if(QUERY_FLAG(op,FLAG_FRIENDLY)) {
  834.         object *owner = get_owner(op);
  835.         if(owner!= NULL && owner->type == PLAYER) {
  836.             sprintf(buf,"Your pet, the %s, is killed by %s.",
  837.             op->name,hitter->name);
  838. #ifdef SOUND_EFFECTS
  839.             play_sound_player_only(owner->contr, SOUND_PET_IS_KILLED);
  840. #endif
  841.             new_draw_info(NDI_UNIQUE, 0,owner,buf);
  842.         }
  843.         remove_friendly_object(op);
  844.         }
  845.         remove_ob(op);
  846.         free_object(op);
  847.     }
  848.     /* Player has been killed! */
  849.     else {
  850.         new_draw_info(NDI_ALL, 1, NULL, buf);
  851.         if(hitter->type==PLAYER) {
  852.         sprintf(buf,"%s the %s",hitter->name,hitter->contr->title);
  853.         strncpy(op->contr->killer,buf,BIG_NAME);
  854.         } else {
  855.         strncpy(op->contr->killer,hitter->name,BIG_NAME);
  856.         op->contr->killer[BIG_NAME-1]='\0';
  857.         }
  858.     }
  859.     } /* End of creature kill processing */
  860.     if(type&AT_GHOSTHIT) {
  861.     /* If the ghosthit didn't do anything, don't remove the creature */
  862.     if(op->immune&AT_GHOSTHIT) return 0;
  863.     if(QUERY_FLAG(hitter,FLAG_FRIENDLY))
  864.         remove_friendly_object(hitter);
  865.     remove_ob(hitter);
  866.     free_object(hitter);
  867.     } 
  868.     /* Lets handle creatures that are splitting now */
  869.     else if(type&AT_PHYSICAL&&!QUERY_FLAG(op, FLAG_FREED)&&QUERY_FLAG(op,FLAG_SPLITTING)) {
  870.     int i;
  871.     int friendly = QUERY_FLAG(op,FLAG_FRIENDLY);
  872.     int unaggressive = QUERY_FLAG(op, FLAG_UNAGGRESSIVE);
  873.     object *owner = get_owner(op);
  874.  
  875.     if(!op->other_arch) {
  876.         LOG(llevError,"SPLITTING without other_arch error.\n");
  877.         return maxdam;
  878.     }
  879.     remove_ob(op);
  880.     for(i=0;i<NROFNEWOBJS(op);i++) { /* This doesn't handle op->more yet */
  881.         object *tmp=arch_to_object(op->other_arch);
  882.         int j;
  883.  
  884.         tmp->stats.hp=op->stats.hp;
  885.         if (friendly) {
  886.         SET_FLAG(tmp, FLAG_FRIENDLY);
  887.         add_friendly_object(tmp);
  888.         tmp->move_type = PETMOVE;
  889.         if (owner!=NULL)
  890.             set_owner(tmp,owner);
  891.         }
  892.         if (unaggressive)
  893.         SET_FLAG(tmp, FLAG_UNAGGRESSIVE);
  894.         j=find_first_free_spot(tmp->arch,op->map,op->x,op->y);
  895.         tmp->x=op->x+freearr_x[j],tmp->y=op->y+freearr_y[j];
  896.         insert_ob_in_map(tmp,op->map);
  897.     }
  898.     if(friendly)
  899.         remove_friendly_object(op);
  900.     free_object(op);
  901.     }
  902.     else if(type & AT_DRAIN &&  hitter->type==GRIMREAPER&&hitter->value++>10) {
  903.       remove_ob(hitter);
  904.       free_object(hitter);
  905.     }
  906.     return maxdam;
  907.   }
  908. }
  909.  
  910. #else /* Not NEW_HIT_PLAYER */
  911.   if(type&AT_ACID&&!( (op->immune&AT_ACID) && (op->protected&AT_ACID) )) { 
  912.     object *tmp;  /*  If someone is both immune and protected from acid, so is his stuff */
  913.     int flag=0;
  914.     for(tmp=op->inv;tmp!=NULL;tmp=tmp->below) {
  915.       if(!QUERY_FLAG(tmp,FLAG_APPLIED)||tmp->immune&AT_ACID||
  916.          (tmp->protected&AT_ACID&&RANDOM()&1))
  917.         continue;
  918.       if(!(tmp->material&M_IRON))
  919.         continue;
  920.       if(tmp->magic< -4) /* Let's stop at -5 */
  921.         continue;
  922.       if(tmp->type==RING||tmp->type==GLOVES||tmp->type==BOOTS||
  923.          tmp->type==GIRDLE||tmp->type==AMULET||tmp->type==WAND||
  924.          tmp->type==ROD||tmp->type==HORN)
  925.         continue; /* To avoid some strange effects */
  926.       if(RANDOM()%(dam+5)>RANDOM()%40) {
  927.         if(op->type==PLAYER) {
  928.           strcpy(buf,"The ");
  929.           strcat(buf,query_name(hitter));
  930.           strcat(buf,"'s acid corrodes your ");
  931.       strcat(buf,query_name(tmp));
  932.       strcat(buf,"!");
  933.     if (op->contr->eric_server > 0)
  934.         esrv_send_item(op, tmp);
  935.       new_draw_info(NDI_UNIQUE, 0,op,buf);
  936.       flag=1;
  937.     }
  938.     tmp->magic--;
  939.       }
  940.     }
  941.     if(flag) {
  942.       if (op->contr->eric_server <= 0)
  943.     draw_all_inventory(op);
  944.       fix_player(op);
  945.     }
  946.   }
  947.   /* How this works is like this:
  948.    * If the race is the same as the slaying, or the object slays undead
  949.    * and and creature is undead, or the creatures archetype name is 
  950.    * the same as the slaying name, then do triple damage.
  951.    *
  952.    * Nov 95 - modified it so that strstr was used to allow comma delimited
  953.    * list. -b.t. 
  954.    *
  955.    * The if statement is really messy.  However, it needs to be there so
  956.    * that the else below operates properly (weapon is something that doesn't
  957.    * slay.)  Before, just hitter->slaying was the first if, which meant a
  958.    * creature wouldn't be immune to anything that slays.
  959.    */
  960.   if (hitter->slaying &&
  961.     ( (op->race != NULL && strstr(op->race,hitter->slaying))||
  962. #ifndef MULTIPLE_GODS
  963.       (strstr(hitter->slaying, undead_name) && QUERY_FLAG(op,FLAG_UNDEAD)) ||
  964. #endif
  965.        (op->arch && op->arch->name!=NULL && 
  966.     strstr(op->arch->name, hitter->slaying))) )
  967.     {
  968.         dam *= 3; /* Ouch 8) */
  969.     }
  970.   else if (op->immune&type)
  971.   {
  972.     /* newtype contains what creature is not immune to from this attack */
  973.     int newtype = type & ~op->immune;
  974.     /*
  975.      * Magic is special, if immune to it, immune to everything containing it
  976.      * Otherwise, only immune if immune to every attacktype included.
  977.      * The middle case of the if is like this:  If the creature is immune to
  978.      * all the attack types on it except magic, creature is still immune.
  979.      * This, if the attack type is fear and magic, and the creature is immune
  980.      * to fear, he will not be damaged at all.
  981.      */
  982.     if (!newtype || (newtype == AT_MAGIC && newtype != type) ||
  983.       (op->immune & AT_MAGIC && type & AT_MAGIC))
  984.       return 0;
  985.     type = newtype;
  986.   }
  987.   if((type&AT_TURN_UNDEAD&&!QUERY_FLAG(op,FLAG_UNDEAD)) 
  988.      || (type&AT_HOLYWORD&&(QUERY_FLAG(op,FLAG_ALIVE)&&  
  989.          (!op->race||!hitter->slaying||!strstr(hitter->slaying,op->race)))))
  990.       return 0;
  991.  
  992.   /* Basically, the next glob of code does saving throw for the attack types */
  993.   if(type&(AT_PARALYZE|AT_FEAR|AT_POISON|AT_CONFUSION|AT_SLOW|
  994.     AT_CANCELLATION|AT_DEPLETE)) 
  995.     if(!op->speed||(!QUERY_FLAG(op, FLAG_MONSTER)&&op->type!=PLAYER)||
  996.        RANDOM()%((type&AT_SLOW)?6:3)||
  997.        /*  the following includes a secret saving throw for magic:
  998.        you get TWO saving throws for magical attacks! */
  999.        (RANDOM()%20+((op->protected&type)?5:1) >= savethrow[op->level]))
  1000.       {
  1001. /* do not bail out immediately if other attack types can succeed */
  1002. type &= ~(AT_PARALYZE|AT_FEAR|AT_POISON|AT_CONFUSION|AT_SLOW|
  1003.       AT_CANCELLATION|AT_DEPLETE);
  1004. if (!type)
  1005.   return 0;
  1006.       }
  1007.   
  1008.   CLEAR_FLAG(op,FLAG_SCARED); /* Or the monster won't hit back */
  1009.   if(get_owner(hitter))
  1010.     op->enemy=hitter->owner;
  1011.   else
  1012.     if(QUERY_FLAG(hitter,FLAG_ALIVE))
  1013.       op->enemy=hitter;
  1014.   if(QUERY_FLAG(op,FLAG_UNAGGRESSIVE) && op->type != PLAYER) {
  1015.     /* The unaggressives look after themselves 8) */
  1016.     CLEAR_FLAG(op, FLAG_UNAGGRESSIVE);
  1017.     npc_call_help(op);
  1018.   }
  1019.   if(dam > 0) {
  1020.     if(op->vulnerable&type)
  1021.       dam*=2;
  1022.     if(op->protected&type)
  1023.       dam/=2;
  1024.     if(op->armour&&type&AT_PHYSICAL)
  1025.       dam=((100-op->armour)*dam)/100;
  1026.     if(dam < 1)
  1027.       dam = RANDOM()&1;
  1028.   }
  1029.   if(type&AT_POISON) {
  1030.     poison_player(op,hitter,dam);
  1031.     type &=~(AT_POISON|AT_MAGIC);
  1032.   }
  1033.   if(type&AT_SLOW) {
  1034.     slow_player(op,hitter,dam);
  1035.     type &=~(AT_SLOW|AT_MAGIC);
  1036.   }
  1037.   if(type&AT_CONFUSION) {
  1038.     confuse_player(op,hitter,dam);
  1039.     type &=~(AT_CONFUSION|AT_MAGIC);
  1040.   }
  1041.   if(type&AT_TURN_UNDEAD || type&AT_HOLYWORD) {
  1042.     object *owner=get_owner(hitter)==NULL?hitter:get_owner(hitter);
  1043.     if(op->level<turn_bonus[owner->stats.Wis]+owner->level)
  1044.     SET_FLAG(op, FLAG_SCARED);
  1045. #if 0
  1046.     if(!(type&~(AT_TURN_UNDEAD|AT_MAGIC))) {
  1047.     op->stats.hp-=dam;
  1048.     return dam;
  1049.     }
  1050. #endif
  1051.   }
  1052.   if(type&AT_FEAR) {
  1053.     SET_FLAG(op, FLAG_SCARED);
  1054.     if(!(type&~(AT_FEAR|AT_MAGIC)))
  1055.       return 0;
  1056.   }
  1057.   if(type&AT_BLIND){
  1058.     if(!QUERY_FLAG(op,FLAG_UNDEAD)
  1059.     &&!QUERY_FLAG(op,FLAG_GENERATOR)) 
  1060.     blind_player(op,hitter,dam);
  1061.     type &=~(AT_BLIND|AT_MAGIC);
  1062.   }
  1063.   if(type&AT_DRAIN) {
  1064.     if(op->stats.exp<=((op->protected & type)?100:50)) {
  1065.       type=type|AT_PHYSICAL;
  1066.       if(op->type==GOLEM)
  1067.     dam=999; /* It's force is "sucked" away. 8) */
  1068. #if 0 /* Leave the damage that gets passed to us.  Even if you can't drain,
  1069.        * we should be able to do real damage
  1070.        */
  1071.       else
  1072.         dam=1;
  1073. #endif
  1074.     } else {
  1075.       if(hitter->stats.hp<hitter->stats.maxhp&&
  1076.          op->level>hitter->level&&
  1077.          RANDOM()%(op->level-hitter->level+3)>3)
  1078.         hitter->stats.hp++;
  1079.       if(!QUERY_FLAG(op,FLAG_WAS_WIZ))
  1080.         add_exp(hitter,op->stats.exp/(100+(op->protected&type)?100:0));
  1081.       add_exp(op,-op->stats.exp/(50+(op->protected&type)?50:0));
  1082.     }
  1083.     if(hitter->type==GRIMREAPER&&hitter->value++>10) {
  1084.       remove_ob(hitter);
  1085.       free_object(hitter);
  1086.     }
  1087.     if(!(type&AT_PHYSICAL))
  1088.       return 0;
  1089.   }
  1090.   if(type&AT_PARALYZE) {
  1091.     paralyze_player(op,hitter,dam);
  1092.     type&=~(AT_PARALYZE|AT_MAGIC);
  1093.   }
  1094.  
  1095.   if(!type) /* We've done everything */
  1096.     return 0;
  1097.   /*  peterm:  death spell.  */
  1098.   if((type&AT_DEATH)&&QUERY_FLAG(op,FLAG_ALIVE)) {
  1099.     deathstrike_player(op,hitter,&dam);
  1100.   }
  1101.  
  1102.   if(type&AT_MAGIC && (RANDOM()%20+1)>=savethrow[op->level])
  1103.     dam=dam/2;
  1104.   op->stats.hp-=dam;
  1105.  
  1106. /* Eneq(@csd.uu.se): Check to see if monster runs away */
  1107.  
  1108.   if ((QUERY_FLAG(op, FLAG_MONSTER) || op->type == PLAYER) &&
  1109.       op->stats.hp<(signed short)(((float)op->run_away/(float)100)*
  1110.       (float)op->stats.maxhp))
  1111.     if (QUERY_FLAG(op, FLAG_MONSTER))
  1112.       SET_FLAG(op, FLAG_RUN_AWAY);
  1113.     else
  1114.       SET_FLAG(op, FLAG_SCARED);
  1115.  
  1116.   if(QUERY_FLAG(op,FLAG_TEAR_DOWN)) {
  1117.     int perc=0;
  1118.     if (!op->stats.maxhp) {
  1119.       LOG(llevError, "TEAR_DOWN wall %s had no maxhp.\n", op->name);
  1120.       perc = 1;
  1121.     } else
  1122.     if(op->arch->animations==0) {
  1123.       if(op->stats.hp<0) {
  1124.               int x = op->x, y = op->y;
  1125.               mapstruct *m = op->map;
  1126.               remove_ob(op); /* Should update LOS */
  1127.               free_object(op);
  1128.               update_position(m, x, y);
  1129.               return dam;
  1130.       }
  1131.       else return dam; }
  1132.       perc = op->arch->animations
  1133.              - ((int)op->arch->animations*op->stats.hp)/op->stats.maxhp;
  1134.     if (perc >= (int) op->arch->animations)
  1135.       perc = op->arch->animations-1;
  1136.     else if (perc < 1)
  1137.       perc = 1;
  1138.     op->face=&new_faces[op->arch->faces[perc]];
  1139.     update_object(op);
  1140.     if(perc==op->arch->animations-1) { /* Reached the last animation */
  1141.       if(op->face==blank_face) {
  1142.     /* If the last face is blank, remove the ob */
  1143.         int x = op->x, y = op->y;
  1144.         mapstruct *m = op->map;
  1145.         remove_ob(op); /* Should update LOS */
  1146.         free_object(op);
  1147.     update_position(m, x, y);
  1148.  
  1149.       } else { /* The last face was not blank, leave an image */
  1150.         CLEAR_FLAG(op, FLAG_BLOCKSVIEW);
  1151.         update_all_los(op->map);
  1152.         CLEAR_FLAG(op, FLAG_NO_PASS);
  1153.         CLEAR_FLAG(op, FLAG_ALIVE);
  1154.       }
  1155.       return dam;
  1156.     }
  1157.   }
  1158.   if(op->stats.hp<0) {
  1159.     object *owner=NULL;
  1160.     dam+=op->stats.hp+1;
  1161.     if(QUERY_FLAG(op,FLAG_BLOCKSVIEW))
  1162.       update_all_los(op->map);
  1163.     if(op->type==DOOR) {
  1164.       op->speed = 0.1;
  1165.       update_ob_speed(op);
  1166.       op->speed_left= -0.05;
  1167.       return dam;
  1168.     }
  1169.     if(op->type==GOLEM) {
  1170.       remove_friendly_object(op);
  1171.       if(get_owner(op)!=NULL)
  1172.         op->owner->contr->golem=NULL;
  1173.       else
  1174.         LOG(llevDebug,"Encountered golem without owner.\n");
  1175.       remove_ob(op);
  1176.       free_object(op);
  1177.       return dam;
  1178.     }
  1179.     owner=get_owner(hitter);
  1180.     if(owner==NULL)
  1181.       owner=hitter;
  1182.     if(owner->type==PLAYER&&(owner->level/2<op->level||op->stats.exp>1000)) {
  1183.       if(owner!=hitter) { 
  1184.         (void) sprintf(buf,"You killed %s with %s.",op->name,hitter->name);
  1185. #ifdef ALLOW_SKILLS
  1186.         old_hitter = hitter;
  1187.         owner->exp_obj=hitter->exp_obj; 
  1188. #endif
  1189.       } else
  1190.         (void) sprintf(buf,"You killed %s.",op->name);
  1191. #ifdef SOUND_EFFECTS
  1192.       play_sound_map(owner->map, owner->x, owner->y, SOUND_PLAYER_KILLS);
  1193. #endif
  1194.       new_draw_info(NDI_BLACK, 0,owner,buf);
  1195.       if(op->type == PLAYER && hitter != op)
  1196.         change_luck(hitter, -1);
  1197.     }
  1198.     if(get_owner(hitter)!=NULL) {
  1199.       (void) sprintf(buf,"%s killed %s with %s.",hitter->owner->name,op->name,
  1200.               hitter->name);
  1201. #ifdef ALLOW_SKILLS
  1202.       old_hitter = hitter;
  1203.       owner->exp_obj=hitter->exp_obj;
  1204. #endif
  1205.       hitter=hitter->owner;
  1206.     }
  1207.     else
  1208.       (void) sprintf(buf,"%s killed %s.",hitter->name,op->name);
  1209.     if(hitter!=op&&!QUERY_FLAG(op, FLAG_WAS_WIZ)) {
  1210.       int exp=op->stats.exp;
  1211.       if(hitter->level>op->level)
  1212.         exp=(exp*(op->level+1))/MAX(hitter->level+1, 1);
  1213.  
  1214. /* new exp system in here. Try to insure the right skill is modifying gained exp */ 
  1215. #ifdef ALLOW_SKILLS 
  1216.       if(hitter->type==PLAYER && !old_hitter) 
  1217.     exp = calc_skill_exp(hitter,op); 
  1218.       /* case for attack spells, summoned monsters killing */ 
  1219.       if (old_hitter && hitter->type==PLAYER) {    
  1220.     object *old_skill = hitter->chosen_skill; 
  1221.     hitter->chosen_skill=old_hitter->chosen_skill;
  1222.     exp = calc_skill_exp(hitter,op); 
  1223.     hitter->chosen_skill = old_skill;
  1224.       }
  1225. #endif /* ALLOW_SKILLS */
  1226.  
  1227.       /* Really don't give much experience for killing other players */
  1228.       if (op->type==PLAYER)
  1229.     exp/=10;
  1230. #ifdef SIMPLE_PARTY_SYSTEM
  1231.       exp=exp/2;
  1232.       if(hitter->type!=PLAYER || hitter->contr->party_number<=0)
  1233.     add_exp(hitter,exp);
  1234.       else {
  1235.     int shares=0,count=0;
  1236.     player *pl;
  1237.     int no=hitter->contr->party_number;
  1238.     for(pl=first_player;pl!=NULL;pl=pl->next)
  1239.       if(pl->ob->contr->party_number==no && (pl->ob->map == hitter->map))
  1240.         {
  1241.           count++;
  1242.           shares+=(pl->ob->level+4);
  1243.         }
  1244.     if(count==1 || shares>exp)
  1245.       add_exp(hitter,exp);
  1246.     else {
  1247.       int share=exp/shares,given=0,nexp;
  1248.       for(pl=first_player;pl!=NULL;pl=pl->next)
  1249.         if(pl->ob->contr->party_number==no && (pl->ob->map == hitter->map))
  1250.           {
  1251.         nexp=(pl->ob->level+4)*share;
  1252.         add_exp(pl->ob,nexp);
  1253.         given+=nexp;
  1254.         if(pl->ob!=hitter)
  1255.           draw_stats(pl->ob);
  1256.           }
  1257.       exp-=given;
  1258.       add_exp(hitter,exp);
  1259.     }
  1260.       }
  1261. #else /* SIMPLE_PARTY_SYSTEM */
  1262.       add_exp(hitter,exp/2);
  1263. #endif /* SIMPLE_PARTY_SYSTEM */
  1264.     }
  1265.     if(hitter->type==PLAYER)
  1266.       draw_stats(hitter);
  1267.     if(op->type!=PLAYER) {
  1268.       new_draw_info(NDI_ALL, 10, NULL, buf);
  1269.       if(QUERY_FLAG(op,FLAG_FRIENDLY)) {
  1270.         object *owner = get_owner(op);
  1271.         if(owner!= NULL && owner->type == PLAYER) {
  1272.           sprintf(buf,"Your pet, the %s, is killed by %s.",
  1273.                   op->name,hitter->name);
  1274. #ifdef SOUND_EFFECTS
  1275.       play_sound_player_only(owner->contr, SOUND_PET_IS_KILLED);
  1276. #endif
  1277.           new_draw_info(NDI_UNIQUE, 0,owner,buf);
  1278.         }
  1279.         remove_friendly_object(op);
  1280.       }
  1281.       remove_ob(op);
  1282.       free_object(op);
  1283.     }
  1284.     else {
  1285.       new_draw_info(NDI_ALL, 1, NULL, buf);
  1286.       if(hitter->type==PLAYER) {
  1287.         sprintf(buf,"%s the %s",hitter->name,hitter->contr->title);
  1288.         strncpy(op->contr->killer,buf,BIG_NAME);
  1289.       } else {
  1290.         strncpy(op->contr->killer,hitter->name,BIG_NAME);
  1291.         op->contr->killer[BIG_NAME-1]='\0';
  1292.       }
  1293.     }
  1294.   }
  1295.   if(type&AT_GHOSTHIT) {
  1296.     if(op->immune&AT_GHOSTHIT) return 0;  /*  allows immunity to ghosthit */
  1297.     if(QUERY_FLAG(hitter,FLAG_FRIENDLY))
  1298.       remove_friendly_object(hitter);
  1299.     remove_ob(hitter);
  1300.     free_object(hitter);
  1301.   } else if(type&AT_PHYSICAL&&!QUERY_FLAG(op, FLAG_FREED)&&QUERY_FLAG(op,FLAG_SPLITTING)) {
  1302.     int i;
  1303.     int friendly = QUERY_FLAG(op,FLAG_FRIENDLY);
  1304.     int unaggressive = QUERY_FLAG(op, FLAG_UNAGGRESSIVE);
  1305.     object *owner = get_owner(op);
  1306.     if(!op->other_arch) {
  1307.       LOG(llevError,"SPLITTING without other_arch error.\n");
  1308.       return dam;
  1309.     }
  1310.     remove_ob(op);
  1311.     for(i=0;i<NROFNEWOBJS(op);i++) { /* This doesn't handle op->more yet */
  1312.       object *tmp=arch_to_object(op->other_arch);
  1313.       int j;
  1314.       tmp->stats.hp=op->stats.hp;
  1315.       if (friendly) {
  1316.         SET_FLAG(tmp, FLAG_FRIENDLY);
  1317.         add_friendly_object(tmp);
  1318.         tmp->move_type = PETMOVE;
  1319.         if (owner!=NULL)
  1320.           set_owner(tmp,owner);
  1321.       }
  1322.       if (unaggressive)
  1323.         SET_FLAG(tmp, FLAG_UNAGGRESSIVE);
  1324.       j=find_first_free_spot(tmp->arch,op->map,op->x,op->y);
  1325.       tmp->x=op->x+freearr_x[j],tmp->y=op->y+freearr_y[j];
  1326.       insert_ob_in_map(tmp,op->map);
  1327.     }
  1328.     if(friendly)
  1329.       remove_friendly_object(op);
  1330.     free_object(op);
  1331.   }
  1332.   if(type&AT_CANCELLATION) {
  1333.     cancellation(op);
  1334.   }
  1335.   if (type & AT_DEPLETE)
  1336.     drain_stat(op);
  1337.   return dam;
  1338. }
  1339. #endif
  1340.  
  1341.  
  1342. void poison_player(object *op, object *hitter, int dam)
  1343. {
  1344.   archetype *at = find_archetype("poisoning");
  1345.   object *tmp=present_arch_in_ob(at,op);
  1346.  
  1347.     if(tmp==NULL) {
  1348.       if((tmp=arch_to_object(at))==NULL)
  1349.         LOG(llevError,"Failed to clone arch poisoning.\n");
  1350.       else {
  1351.         tmp = insert_ob_in_ob(tmp,op);
  1352.     /*  peterm:  give poisoning some teeth.  It should
  1353.         be able to kill things better than it does:
  1354.         damage should be dependent something--I choose to
  1355.         do this:  if it's a monster, the damage from the
  1356.         poisoning goes as the level of the monster/2.
  1357.         If anything else, goes as damage. */
  1358.  
  1359.     if(QUERY_FLAG(hitter,FLAG_ALIVE))
  1360.        tmp->stats.dam += hitter->level/2;
  1361.      else
  1362.        tmp->stats.dam = dam;
  1363.  
  1364.     set_owner(tmp,hitter);   /*  so we get credit for poisoning kills */
  1365.     tmp->stats.food+=dam;  /*  more damage, longer poisoning */
  1366.  
  1367.         if(op->type==PLAYER) {
  1368.           tmp->stats.Con= -(dam/4+1);
  1369.           tmp->stats.Str= -(dam/3+2);
  1370.           tmp->stats.Dex= -(dam/6+1);
  1371.           tmp->stats.Int= -dam/7;
  1372.           SET_FLAG(tmp,FLAG_APPLIED);
  1373.           fix_player(op);
  1374.           new_draw_info(NDI_UNIQUE, 0,op,"You suddenly feel very ill.");
  1375.         }
  1376.       }
  1377.       tmp->speed_left=0;
  1378.     }
  1379.     else
  1380.       tmp->stats.food++;
  1381. }
  1382.  
  1383. void slow_player(object *op,object *hitter,int dam)
  1384. {    archetype *at = find_archetype("slowness");
  1385.     object *tmp;
  1386.     if(at == NULL) {
  1387.       LOG(llevError,"Can't find slowness archetype.\n");
  1388.     }
  1389.     if((tmp=present_arch_in_ob(at,op)) == NULL) {
  1390.       tmp = arch_to_object(at);
  1391.       tmp = insert_ob_in_ob(tmp,op);
  1392.       new_draw_info(NDI_UNIQUE, 0,op,"The world suddenly moves very fast!");
  1393.     } else
  1394.       tmp->stats.food++;
  1395.     SET_FLAG(tmp, FLAG_APPLIED);
  1396.     tmp->speed_left=0;
  1397.     fix_player(op);
  1398. }
  1399.  
  1400. void confuse_player(object *op, object *hitter, int dam)
  1401. {
  1402.     object *tmp;
  1403.     tmp = present_in_ob(CONFUSION,op);
  1404.     if(!tmp) {
  1405.       tmp = get_archetype("confusion");
  1406.       tmp = insert_ob_in_ob(tmp,op);
  1407.     }
  1408.     tmp->stats.food += 5;
  1409.     if( tmp->stats.food > 30)
  1410.       tmp->stats.food = 30;
  1411.     if(op->type == PLAYER && !QUERY_FLAG(op,FLAG_CONFUSED))
  1412.       new_draw_info(NDI_UNIQUE, 0,op,"You suddenly feel very confused!");
  1413.     SET_FLAG(op, FLAG_CONFUSED);
  1414. }
  1415.  
  1416. void blind_player(object *op, object *hitter, int dam)
  1417. {
  1418.     object *tmp,*owner;
  1419.  
  1420.     tmp = present_in_ob(BLINDNESS,op);
  1421.     if(!tmp) { 
  1422.       tmp = get_archetype("blindness");
  1423.       SET_FLAG(tmp, FLAG_BLIND);
  1424.       SET_FLAG(tmp, FLAG_APPLIED);
  1425.       tmp = insert_ob_in_ob(tmp,op);
  1426.       change_abil(op,tmp);   /* Mostly to display any messages */
  1427.       fix_player(op);        /* This takes care of some other stuff */
  1428.  
  1429.       if(hitter->owner) owner = get_owner(hitter);
  1430.       else owner = hitter;
  1431.  
  1432.       new_draw_info_format(NDI_UNIQUE,0,owner,
  1433.       "Your attack blinds %s!",query_name(op));
  1434.     } 
  1435.     tmp->stats.food += dam;
  1436.     if(tmp->stats.food > 10) tmp->stats.food = 10;
  1437. }
  1438.  
  1439. void paralyze_player(object *op, object *hitter, int dam) 
  1440. {    object *tmp;
  1441.     if((tmp=present(PARAIMAGE,op->map,op->x,op->y))==NULL) {
  1442.       tmp=clone_arch(PARAIMAGE);
  1443.       tmp->x=op->x,tmp->y=op->y;
  1444.       insert_ob_in_map(tmp,op->map);
  1445.     }
  1446.     op->speed_left-=(float)FABS(op->speed)*(dam*3);
  1447.     tmp->stats.food+=(signed short) (dam*3)/op->speed;
  1448.     if(op->speed_left< -(FABS(op->speed)*40)) {
  1449.       op->speed_left  = (float) -(FABS(op->speed)*40);
  1450.       tmp->stats.food = (signed short) (40/FABS(op->speed));
  1451.     }
  1452. }
  1453.  
  1454. void deathstrike_player(object *op, object *hitter, int *dam) 
  1455. {    /*  The intention of a death attack is to kill outright things
  1456.     **  that are a lot weaker than the attacker, have a chance of killing
  1457.     **  things somewhat weaker than the caster, and no chance of
  1458.     **  killing something equal or stronger than the attacker.
  1459.     **  Also, if a deathstrike attack has a slaying, any monster
  1460.     **  whose name or race matches a comma-delimited list in the slaying
  1461.     **  field of the deathstriking object  */
  1462.  
  1463.     int atk_lev, def_lev, kill_lev;
  1464.     if(hitter->slaying) 
  1465.     if(!( (QUERY_FLAG(op,FLAG_UNDEAD)&&strstr(hitter->slaying,"undead")) ||
  1466.         (op->race&&strstr(hitter->slaying,op->race))))    return;
  1467.     def_lev = op->level;
  1468. /*  atk_lev  = (hitter->level)/2; */ 
  1469.     atk_lev  = SK_level(hitter)/2;
  1470.     if(atk_lev >= def_lev ){
  1471.       kill_lev = RANDOM() % atk_lev;
  1472.       if(kill_lev >= def_lev){
  1473.      *dam = op->stats.hp+10; /* take all hp. they can still save for 1/2 */
  1474.      *dam *= kill_lev / (def_lev == 0 ? 1 : def_lev); /* extra deadly? */
  1475.       }
  1476.     } else {
  1477.       *dam = 0;  /* no harm done */
  1478.     }
  1479. }
  1480.